package com.dtflys.easyel.exception;

import com.dtflys.easyel.compile.EasyElSource;
import com.dtflys.easyel.compile.EasyElSourceLine;
import com.dtflys.easyel.compile.EasyElSourcePosition;
import com.dtflys.easyel.runtime.EasyElRuntimeContext;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @author gongjun[jun.gong@thebeastshop.com]
 * @since v1.0.0
 */
public class EasyElException extends RuntimeException {

//    private final static String ERROR_LINE_COLOR = AnsiHelper.fg(Ansi.Color.RED);
//    private final static String EASYEL_MARK_COLOR = AnsiHelper.fg(Ansi.Color.CYAN);
//    private final static String SOURCE_COLOR = AnsiHelper.fg(Ansi.Color.YELLOW);
//    private final static String BOLD = AnsiHelper.bold();
//    private final static String RESET = AnsiHelper.reset();


    public EasyElException(String msg) {
        this(true, msg);
    }


    public EasyElException(String msg, Throwable cause) {
        this(true, msg, cause);
    }


    public EasyElException(boolean autoPrefix, String msg) {
        super(autoPrefix ? getErrorMsg(msg) : msg);
    }


    public EasyElException(boolean autoPrefix, String msg, Throwable cause) {
        super(autoPrefix ? getErrorMsg(msg) : msg, cause);

        Class clazz = getClass();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (method.getName().equals("printEnclosedStackTrace")) {
                method.setAccessible(true);
            }
        }
    }


    protected static String getErrorMsg(String msg) {
        return "\n  " + getEasyElMark() + " error: " + msg;
    }


    protected static String getErrorMsg(EasyElRuntimeContext context, EasyElSourcePosition position, String msg) {
        return "\n  " + getEasyElMark() +" error[runtime]: " + msg + "\n\n" +
                getIndentSpace(9) + getBody(context.getSource(), position);
    }

    protected static String getBody(EasyElSource source, EasyElSourcePosition position) {
        return  "--> "
                + source.getSourceName()
                + ":"
                + position.getStartLine() + ":" + position.getStartColumn()
//                + ")"
                + "\n\n"
                + getSourcePart(source, position, 16);
    }

    protected static String getEasyElMark() {
        return "["
//                + EASYEL_MARK_COLOR + BOLD
                + "EASYEL"
//                + RESET
                + "]";
    }



    protected static String getSourcePart(EasyElSource source, EasyElSourcePosition position, int indent) {
        List<EasyElSourceLine> lineList = source.getLineList(0, position.getEndLine());
        if (lineList.isEmpty()) {
            return "";
        }
        StringBuilder builder = new StringBuilder();

        int startLine = position.getStartLine();
        int startColumn = position.getStartColumn();
        for (EasyElSourceLine line : lineList) {
            builder.append(getIndentSpace(indent));
//            builder.append(SOURCE_COLOR);
            builder.append(line.getLine());

            if (line.getLineNumber() == startLine) {
                builder.append('\n');
                builder.append(getIndentSpace(indent));
                for (int i = 0; i < startColumn; i++) {
                    builder.append(' ');
                }
//                builder.append(ERROR_LINE_COLOR);
                for (int i = startColumn; i < position.getEndColumn(); i++) {
                    builder.append('^');
                }
            }
//            builder.append(RESET);
            builder.append('\n');
        }

        return builder.toString();
    }

    protected static String getIndentSpace(int indent) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < indent; i++) {
            builder.append(' ');
        }
        return builder.toString();
    }

    @Override
    public String toString() {
//        AnsiHelper.stopAnsiConsole();
        return getMessage();
    }

}
